<?php

/**
 * Database Storage stream for Logging
 *
 * PHP versions 5
 * CAKEPHP versions 2.x
 * 
 * Green CMS - Content Management System and Framework Powerfull by Cakephp
 * Copyright 2012, GREEN GLOBAL CO., LTD (toancauxanh.vn)
 * 
 * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author        Technology Lab No.I <tech1@toancauxanh.vn>
 * @link          
 * @package       Green.Log
 * @since         Green v 1.0
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
App::uses('CakeLogInterface', 'Log');
App::uses('ClassRegistry', 'Utility');

/**
 * File Storage stream for Logging.  Writes logs to different files
 * based on the type of log it is.
 * 
 */
class DatabaseLog implements CakeLogInterface {

    /**
     * Allowed log type , an empty array to allow all
     *
     * @var array
     */
    public $types = array();

    /**
     * Config fields table of logger
     *
     * @var array
     */
    public $fields = array(
        'type' => 'type',
        'message' => 'message',
        'params' => 'params',
        'location' => 'location',
        'hostname' => 'hostname',
        'user_id' => 'user_id'
    );

    /**
     * User table primary key
     *
     * @var string
     */
    public $foreignKey = 'id';

    /**
     * Total log limit , default 0 to unlimited
     *
     * @var integer
     */
    public $limit = 0;

    /**
     * Model adapter save log
     *
     * @var Model
     */
    protected $_Model = null;

    /**
     * Runtime requested
     *
     * @var array
     */
    protected $_runtime = array();

    /**
     * Constructs a new Database Logger
     *
     * Options
     *
     * - `limit` Total log limit
     * - `fields` Config fields table of logger
     * - `types` System log type
     *
     * @param array $options Options for the DatabaseLog, see above.
     */
    public function __construct($options = array()) {
        $modelClass = 'Report';
        if (!empty($options['model']) && is_string($options['model'])) {
            $modelClass = $options['model'];
        }
        unset($options['model']);
        foreach ($options as $key => $config) {
            if (isset($this->{$key}) && is_array($this->{$key})) {
                $config = array_merge($this->{$key}, (array) $config);
            }
            $this->{$key} = $config;
        }
        $this->_Model = ClassRegistry::init($modelClass, true);
        if (!$this->_Model) {
            throw new MissingModelException(__d('debug', 'Model %s config for Database Log could not be found.', $modelClass));
        }
    }

    /**
     * Implements writing to log.
     *
     * @param string $type The type of log you are making.
     * @param mixel $params
     *  - An string message you want to log
     *  - An array message and paramater to log with i18n.
     *    i.e. array('vsprint message %s/%s',param1,prams2)
     * @return boolean success of write.
     */
    public function write($type, $params) {
        if (empty($type) || (!empty($this->types) && empty($this->types[$type]))) {
            return false;
        }

        $this->_initRuntime();

        $params = (array) $params;
        $message = array_shift($params);
        $data = array_merge($this->_runtime, array(
            $this->fields['message'] => $message,
            $this->fields['type'] => $type));
        if ($params != array()) {
            $data[$this->fields['params']] = serialize($params);
        }
        $this->_Model->create();
        if (empty($message) || !$this->_Model->save($data)) {
            return false;
        }
        if ($this->limit > 0) {
            $primaryKey = $this->_Model->alias . '.' . $this->_Model->primaryKey;
            $data = $this->_Model->find('first', array(
                'callbacks' => false,
                'recursive' => -1,
                'order' => $primaryKey . ' DESC',
                'offset' => $this->limit - 1,
                'limit' => 1,
                'fields' => array($primaryKey)));
            if (isset($data[$this->_Model->alias][$this->_Model->primaryKey])) {
                $this->_Model->deleteAll(array($primaryKey . ' <' => $data[$this->_Model->alias][$this->_Model->primaryKey]), false, false);
            }
        }
        return true;
    }

    /**
     * initialize runtime requested.
     *
     * @return void
     */
    protected function _initRuntime() {
        if (empty($this->_runtime[$this->fields['hostname']])) {
            if (!($request = Router::getRequest())) {
                $request = new CakeRequest(null, false);
            }
            $this->_runtime[$this->fields['hostname']] = Router::url($request->here(false), true);
        }
        if (empty($this->_runtime[$this->fields['location']])) {
            $this->_runtime[$this->fields['location']] = env('REMOTE_ADDR');
        }
        if (empty($this->_runtime[$this->fields['user_id']]) && class_exists('AuthComponent')) {
            $this->_runtime[$this->fields['user_id']] = AuthComponent::user($this->foreignKey);
        }
    }

}